#ifndef __MYIO_H__
#define __MYIO_H__

#include "wchar.h"
#include <string.h>
#include "stdlib.h"
#include "common/vector3.h"
#include "StrKey.h"
#include <math.h>
#include "common/common_defs.h"
#include "common/common_types.h"

int const LEN_STR = 256;
int const MAP = 200;

inline float rand_l(float x_min, float len) {
    return ((float) rand() / RAND_MAX) * len + x_min;
}

class IFr {
public:
    IFr(float P1, float P2, float Sigma, float Eps, char T);
    IFr(int pid);
    float Potential(float x, char T) const {
        return _Potential(eps, sigma, p1, p2, pTp, x, T);
    }
    IFr(int i, int j, int k);
    void Set(float P1, float P2, float s, float e, char T);
    char getpTp() const;

    static float Potential(const ForceInfo& fInfo, float x, char T) {
        return _Potential(fInfo.Eps, fInfo.Sigma, fInfo.P1, fInfo.P2, fInfo.pTp, x, T);
    }

    ForceInfo getForceInfo() const {
        ForceInfo result;
        result.Eps = eps;
        result.Sigma = sigma;
        result.P1 = p1;
        result.P2 = p2;
        result.pTp = pTp;
        return result;
    }

    int I, J;
    int pID;
private:
    static float _Potential(float eps, float sigma, float p1, float p2, char pTp, float x, char T) {
        switch (pTp) {
            case 'L': {
                switch (T) {
                    case 'U': {
                        float sigma_per_x_6 = sigma / x;
                        sigma_per_x_6 *= sigma_per_x_6 * sigma_per_x_6;
                        sigma_per_x_6 *= sigma_per_x_6;
                        return 4 * eps * sigma_per_x_6 * (sigma_per_x_6 - 1);
                        //return 4 * eps * (pow(sigma / x, 12) - pow(sigma / x, 6));
                    }
                    case 'F': {
                        float sigma_per_x = sigma / x;
                        float sigma_per_x_6 = sigma_per_x;
                        sigma_per_x_6 *= sigma_per_x_6 * sigma_per_x_6;
                        sigma_per_x_6 *= sigma_per_x_6;
                        return -24 * eps / sigma * sigma_per_x * sigma_per_x_6 * (2.0f * sigma_per_x_6 - 1);
                        //return -24 * eps / sigma * (2.0f * pow((sigma / x), 13) - pow((sigma / x), 7));
                    }
                    case 'D': {
                        float sigma_per_x_2 = sigma / x;
                        sigma_per_x_2 *= sigma_per_x_2;
                        float sigma_per_x_4 = sigma_per_x_2 * sigma_per_x_2;
                        float sigma_per_x_8 = sigma_per_x_4 * sigma_per_x_4;
                        return 24 * eps / sigma / sigma * sigma_per_x_8 * (26 * sigma_per_x_4 * sigma_per_x_2 - 7);
                        //return 24 * eps / sigma / sigma * (26 * pow(sigma / x, 14) - 7 * pow(sigma / x, 8));
                    }
                    case 'R':
                        return sigma;
                }
            }
                break;
            case 'K': {
                switch (T) {
                    case 'F':
                        return (x - sigma) * eps;
                    case 'U':
                        return (x - sigma) * (x - sigma) * eps / 2;
                }
            }
                break;
        }
        return 0;
    }

    IFr(const IFr&);
    float eps, sigma, p1, p2;
    char pTp;
};

typedef IFr * IForce;

struct user {
    char FName[15];
    char LName[15];
};
struct info {
    char ModelName[LEN_STR];
    user Users[1];
};

struct IDName {
    int ComponentID;
    float Mass;
    char CompName[LEN_STR];
};

struct SubListItem {
    int NUM_OF_STATE[10];
    int NUM_OF_COMPONENT;
    IForce ColFunc[MAX_FORCE_INDEX][MAX_FORCE_INDEX];
    IDName idName[10];
    int TubeComp;
    int nM;
};

struct MolInfo {
    short privID;
    short cId;
    char symbol[2];
    Vector3 p;
};

struct MolDscr {
    char mName[LEN_STR];
    int rank;
    int EfRank;

    float Portion;

    MolInfo molSrc[3800];

    IForce ** dCnt;
    IForce *** aCnt;

    IDName molCompos[10];
};

struct TubeDscr {
    char mName[LEN_STR];
    int rank;
    int EfRank;
    float Temp;
    float RelTime;
    float Vol;
    float Rad;
    float Len;
    int cicl;
    int NumOfPair;

    MolInfo molSrc[10000];
    IDName molCompos[10];
    IForce * dCnt;
};
//////
class FileReader {
public:
    FileReader(FILE* f);

    float readFloat(const char* key, bool* ok = NULL);
    float* readArray(const char* key, int length, bool* ok = NULL);

    bool readString(const char* key, char buf[LEN_STR]);

private:
    FILE* _file;
};
//////////////////////////

class MainInit {
public:
    MainInit(FILE * inf, FILE * mol, FILE * interMol, FILE * log);
    bool initAbout();

    bool initSub();
    bool findSub();
    bool initPtnl();

    bool initFlow();

    bool initTech();

    const SubListItem& getSub() const {
        return sub;
    }
    MolDscr * getMDscr();
    const info& getInfo() const {
        return Info;
    }

    TubeDscr* Tube;
    info Info;
    FileReader inData;
    FileReader inMol;
protected:

    FILE * infoF, *mol, *interMol, *log;
    char * err;

    MolDscr molArr[10];

    int numMol;
    SubListItem sub;
};

struct mrsCell {
    float RoMA[MAP];
    float TempMA[MAP];
    Vector3 VelMA[MAP];
    int Ch;
};

struct toVisual {
    Vector3 pos;
    Vector3 vel;
    int cID;
    float M;
};
typedef toVisual* pToVisual;
class Measurer {
public:
    Measurer(info inf, SubListItem sub, TubeDscr * td, MolDscr* md, const Vector3& LB, const Vector3& RB);
    void outHead();
    void outSub();
    void outChl();
    void Measurement(toVisual * sys, int end);
    void outField(int ITER);
    void closeField();

protected:
    FILE * HeadF, *SubF, *ChF, *ChXML, *FieldF;
    FILE * tempF;
    MolDscr * mDscr;
    TubeDscr * tDscr;
    SubListItem Sub;
    info Inf;
    Vector3 LB, RB;
    int MAch;
    float hX, hY, hZ, MaxF, MinF;

private:
    mrsCell *** mrsNet;
    int netSizeX, netSizeY, netSizeZ;
};

#endif // __MYIO_H__
